package com.cdu.service.impl;

import com.cdu.commons.MallConstants;
import com.cdu.commons.ServiceCode;
import com.cdu.commons.ServiceException;
import com.cdu.mapper.UserMapper;
import com.cdu.pojo.dto.LoginDTO;
import com.cdu.pojo.dto.UserRegDTO;
import com.cdu.pojo.entity.User;
import com.cdu.pojo.vo.LoginUserVO;
import com.cdu.pojo.vo.UserInfoVO;
import com.cdu.service.UserService;
import com.cdu.utils.JwtUtils;
import com.cdu.utils.MD5Utils;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.rmi.ServerException;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ProjectName: cdu-app
 * @Titile: UserServiceImpl
 * @Author: Administrator
 * @Description: 用户业务类
 */
@Service //语义化，代表的是业务层
public class UserServiceImpl implements UserService {
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public void reg(UserRegDTO userRegDTO) {
        //判断密码是否一致
        if (!userRegDTO.getPassword().equals(userRegDTO.getRePassword())) {
            //密码与确认密码不一致
            throw new ServiceException("确认密码与密码不一致", ServiceCode.DATA_CHECK_ERROR);
        }
        //密码与确认密码一致
        //对密码进行加密
        //获取盐值
        String salt = UUID.randomUUID().toString().replace("-", "");
        //使用盐值+密码+散列次数进行加密
        String password = MD5Utils.enctype(userRegDTO.getPassword(), salt, MallConstants.HASH_TIME);
        //封装用户注册的信息
        User user = new User();
        user.setUsername(userRegDTO.getUsername());
        user.setPassword(password);
        user.setSalt(salt);
        user.setIsDelete(MallConstants.IS_NOT_DELETE);// 0代表不删除，1：删除
        user.setCreatedUser(userRegDTO.getUsername());
        //将时间在数据库新增数据时进行设置

        //调用持久层新增用户信息
        int result = 0;
        try {
            result = userMapper.insert(user);
        } catch (Exception e) {
            throw new ServiceException("注册失败:数据库错误", ServiceCode.INSERT_ERROR);
        }
        if (result != 1) {
            throw new ServiceException("注册失败:SQL语句执行失败", ServiceCode.INSERT_ERROR);
        }
        //执行成功了
    }

    @Override
    public LoginUserVO login(LoginDTO loginDTO) {
        //根据用户名查询用户
        User user = userMapper.getUserByName(loginDTO.getUsername());
        if (user == null) {
            throw new ServiceException("登录失败:用户名不存在", ServiceCode.DATA_NOT_FOUND);
        }
        //用户存在
        //将登录密码进行加密
        String loginPwd = MD5Utils.enctype(loginDTO.getPassword(), user.getSalt(), MallConstants.HASH_TIME);
        //判断密码
        if (!loginPwd.equals(user.getPassword())) {
            throw new ServiceException("登录失败:密码错误", ServiceCode.LOGIN_ERROR);
        }
        //密码ok的
        //封装登录成功后的用户VO
        LoginUserVO loginUserVO = new LoginUserVO();
        loginUserVO.setUsername(user.getUsername());
        loginUserVO.setId(user.getId());
        loginUserVO.setAvatar(user.getAvatar());//头像的路径
        //生成用户的身份
        String token = JwtUtils.generateToken(user);
        //身份
        loginUserVO.setToken(token);
        return loginUserVO;
    }

    @Override
    public UserInfoVO getUserInfo(User user) {
        //根据用户名查询信息
        User loginUser = userMapper.getUserByName(user.getUsername());
        //封装个人资料
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setUsername(loginUser.getUsername());
        userInfoVO.setPhone(loginUser.getPhone());
        userInfoVO.setEmail(loginUser.getEmail());
        userInfoVO.setGender(loginUser.getGender());
        return userInfoVO;
    }
//    //注入保存头像的路径
//    //TODO
//    @Setter
//    @Value("${avatar.save.path}")
//    private String saveDir;
//
//    // 在类级别定义原子类变量，用于保证数据库更新操作的原子性，记录成功更新的次数
//    private final AtomicInteger atomicResult = new AtomicInteger(0);
//
//
//    @Override
//    public String upload(MultipartFile avatar, User user) {
//        if (avatar == null || avatar.isEmpty()) {
//            throw new ServiceException("头像不能为空", ServiceCode.AVATAR_IS_NULL);
//        }
//
//        // 获取文件名
//        String filename = avatar.getOriginalFilename();
//        log.debug("上传的文件名：{}", filename);
//
//        // UUID + 截取后缀，生成唯一文件名
//        filename = UUID.randomUUID().toString().replace("-", "")
//                + filename.substring(filename.lastIndexOf("."));
//        log.debug("上传的文件新名：{}", filename);
//
//        // 创建保存文件的父目录
//        File parentDir = new File(saveDir);
//        if (!parentDir.exists()) {
//            // 逐级创建目录
//            parentDir.mkdirs();
//        }
//
//        // 保存文件
//        File file = new File(saveDir, filename);
//        try {
//            avatar.transferTo(file);
//        } catch (IOException e) {
//            log.debug("上传文件失败：{}", e.getMessage());
//            throw new ServiceException("上传文件失败", ServiceCode.FILE_UPLOAD_ERROR);
//        }
//
//        // 封装用户数据
//        user.setAvatar(filename);
//        user.setModifiedUser(user.getUsername());
//
//        // 使用多线程进行数据库更新操作，考虑事务，使用原子类
//        Thread updateThread = new Thread(() -> {
//            try {
//                int result = userMapper.setAvatar(user);
//                // 使用原子类来原子性地更新成功更新次数，保证在多线程下计数准确
//                atomicResult.getAndAdd(result);
//            } catch (Exception e) {
//                // 更新失败，删除已上传的头像文件
//                if (file.exists()) {
//                    file.delete();
//                }
//                throw new ServiceException("上传头像失败:数据库执行SQL语句失败", ServiceCode.FILE_UPLOAD_ERROR);
//            }
//        });
//        updateThread.start();
//        try {
//            // 等待数据库更新线程执行完成
//            updateThread.join();
//        } catch (InterruptedException e) {
//            Thread.currentThread().interrupt();
//            throw new ServiceException("数据库更新线程被中断", ServiceCode.FILE_UPLOAD_ERROR);
//        }
//
//        // SQL语句执行成功，但结果不对（预期成功更新次数为1），则认为更新失败
//        if (atomicResult.get()!= 1) {
//            // 删除已上传的头像文件
//            if (file.exists()) {
//                file.delete();
//            }
//            throw new ServiceException("上传头像失败:数据库更新失败", ServiceCode.FILE_UPLOAD_ERROR);
//        }
//
//        return filename;
//    }

   //注入保存头像的路径
   //TODO
    @Setter
    @Value("${avatar.save.path}")
    private String saveDir;
//
//    // 在类级别定义原子类变量，用于保证数据库更新操作的原子性，记录成功更新的次数
//    private final AtomicInteger atomicResult = new AtomicInteger(0);
    @Override
    public String upload(MultipartFile avatar, User user) {
        if(avatar==null || avatar.isEmpty()){
            throw new ServiceException("头像不能为空",ServiceCode.AVATAR_IS_NULL);
        }
        // 获取文件名
        String filename = avatar.getOriginalFilename();
        log.debug("上传的文件名：{}",filename);
        // UUID+截取后缀，生成唯一文件名
        filename = UUID.randomUUID().toString().replace("-","") + filename.substring(filename.lastIndexOf("."));
        log.debug("上传的文件新名：{}",filename);
        // 创建保存的父目录
        File parentDir = new File(saveDir);
        if(!parentDir.exists()){
            parentDir.mkdirs();
        }
        // 保存文件
        File file = new File(saveDir, filename);
        try {
            avatar.transferTo(file);
        } catch (IOException e) {
            log.debug("上传文件失败：{}",e.getMessage());
            throw new ServiceException("上传文件失败",ServiceCode.FILE_UPLOAD_ERROR);
        }

        // 封装用户数据
        user.setAvatar(filename);
        user.setModifiedUser(user.getUsername());

        // TODO 为了性能，考虑使用多线程，进行异步操作，但是要考虑事务：使用原子化
        // 使用线程池执行数据库更新操作，并通过原子类记录结果
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        AtomicInteger atomicResult = new AtomicInteger(0);

        Future<?> future = executorService.submit(() -> {
            try {
                int result = userMapper.setAvatar(user);
                atomicResult.addAndGet(result);
            } catch (Exception e) {
                // 更新失败，删除已上传的头像文件
                if(file.exists()){
                    file.delete();
                }
                throw new ServiceException("上传头像失败:数据库执行SQL语句失败",ServiceCode.FILE_UPLOAD_ERROR);
            }
        });

        try {
            // 等待数据库更新线程执行完成
            future.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            // 删除已上传的头像文件
            if(file.exists()){
                file.delete();
            }
            throw new ServiceException("上传头像失败:线程被中断",ServiceCode.FILE_UPLOAD_ERROR);
        } catch (ExecutionException e) {
            // 执行过程中已在子线程中抛出异常并处理文件删除，此处直接抛出即可
            throw new ServiceException("上传头像失败:数据库执行SQL语句失败",ServiceCode.FILE_UPLOAD_ERROR);
        } finally {
            executorService.shutdown();
        }

        // 检查更新结果
        if (atomicResult.get() != 1) {
            // 更新失败，删除已上传的头像文件
            if(file.exists()){
                file.delete();
            }
            throw new ServiceException("上传头像失败:数据库更新失败",ServiceCode.FILE_UPLOAD_ERROR);
        }

        return filename;
    }





    /*修改密码*/
    @Override
    public Integer changePassword(String username, String oldPassword, String newPassword) throws ServerException {
        //查询用户信息
        User user = userMapper.getUserByName(username);
        if (user == null) {
            throw new ServerException("修改失败：用户不存在");
        }
        //判断用户是否被删除
        if (user.getIsDelete().equals(MallConstants.IS_DELETE)){
            throw new ServerException("修改异常：此用户已被禁用");
        }
        //判断新输入的原密码和新密码是否一致
        if (oldPassword.equals(newPassword)){
            throw new ServerException("新密码与原密码一致,请重新输入");
        }
        //判断原密码（先加密后比对）是否输入正确
        String salt = user.getSalt();
        oldPassword = MD5Utils.enctype(oldPassword, salt, MallConstants.HASH_TIME);
        if (!oldPassword.equals(user.getPassword())){
            throw new ServerException("修改异常：原密码输入有误");
        }
        //修改密码为新密码（先加密后修改）
        newPassword = MD5Utils.enctype(newPassword, salt, MallConstants.HASH_TIME);
        Integer row = userMapper.updatePassword(user.getId(), newPassword, user.getUsername());
        return row;
    }

    /*修改用户信息*/
    @Override
    public Integer changeUserInfo(String username,User user) throws ServerException {
        //根据用户名查询用户信息并判断用户是否存在
        User u = userMapper.getUserByName(username);
        if (u==null){
            throw new ServerException("修改异常：用户不存（登录已失效）");
        }
        //判断用户是否被标记已删除
        if (u.getIsDelete().equals(MallConstants.IS_DELETE)){
            throw new ServerException("修改异常：该用户已被禁用");
        }
        //修改信息
        User user1=new User();
        user1.setId(u.getId());
        user1.setModifiedUser(u.getUsername());
        user1.setPhone(user.getPhone());
        user1.setEmail(user.getEmail());
        user1.setGender(user.getGender());
        Integer row = userMapper.updateUserInfo(user1);
        if (row!=1){
            throw new ServerException("修改异常：修改的对象有误");
        }
        return null;
    }
}
